package com.rawchen.interceptor;

import com.rawchen.annotation.AccessLimit;
import com.rawchen.config.RedisKeyConfig;
import com.rawchen.model.vo.Result;
import com.rawchen.service.RedisService;
import com.rawchen.util.IpAddressUtils;
import com.rawchen.util.JacksonUtils;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import java.io.PrintWriter;

/**
 * @Description: 访问控制拦截器
 */
@Component
public class AccessLimitInterceptor implements HandlerInterceptor {
	@Autowired
	private RedisService redisService;

	@Override
	public boolean preHandle(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response,
	                         @NotNull Object handler) throws Exception {
		if (handler instanceof HandlerMethod handlerMethod) {
			AccessLimit accessLimit = handlerMethod.getMethodAnnotation(AccessLimit.class);
			//方法上没有访问控制的注解，直接通过
			if (accessLimit == null) {
				return true;
			}
			int seconds = accessLimit.seconds();
			int maxCount = accessLimit.maxCount();
			String ip = IpAddressUtils.getIpAddress(request);
			String method = request.getMethod();
			String requestURI = request.getRequestURI();
			String redisKey = RedisKeyConfig.createAccessLimitKey(ip, method, requestURI);
			Integer count = redisService.getObjectByValue(redisKey, Integer.class);
			if (count == null) {
				//在规定周期内第一次访问，存入redis
				redisService.incrementByKey(redisKey, 1);
				redisService.expire(redisKey, seconds);
			} else {
				if (count >= maxCount) {
					//超出访问限制次数
					response.setContentType("application/json;charset=utf-8");
					try (PrintWriter out = response.getWriter()) {
						Result result = Result.create(HttpStatus.FORBIDDEN.value(), accessLimit.msg());
						out.write(JacksonUtils.toJsonString(result));
						out.flush();
					}
					return false;
				} else {
					//没超出访问限制次数
					redisService.incrementByKey(redisKey, 1);
				}
			}
		}
		return true;
	}
}